package com.sunwayworld.basemodule.common.eptstorage.acqconfig.service.impl;

import com.sunwayworld.basemodule.common.eptstorage.acqconfig.bean.LimsEquiptAcqConfigInstBean;
import com.sunwayworld.basemodule.common.eptstorage.acqconfig.net.NetEptSender;
import com.sunwayworld.basemodule.common.eptstorage.acqconfig.net.NetEptSenderHelper;
import com.sunwayworld.basemodule.common.eptstorage.acqconfig.service.LimsEquiptAcqConfigInstService;
import com.sunwayworld.basemodule.common.eptstorage.acqconfig.service.LimsEquiptAcqConfigService;
import com.sunwayworld.basemodule.common.eptstorage.acqconfig.service.LimsEquiptSerialNetRecService;
import com.sunwayworld.basemodule.rm.equipment.bean.LimsEquipmentBean;
import com.sunwayworld.basemodule.rm.equipment.bean.LimsEquipmentBean;
import com.sunwayworld.basemodule.rm.equipment.service.LimsEquipmentService;
import com.sunwayworld.cloud.module.equipt.acqconfig.bean.CoreEquiptAcqConfigBean;
import com.sunwayworld.cloud.module.equipt.acqconfig.persistent.dao.CoreEquiptAcqConfigDao;
import com.sunwayworld.cloud.module.equipt.acqconfig.service.impl.CoreEquiptAcqConfigServiceImpl;
import com.sunwayworld.framework.at.annotation.AuditTrailEntry;
import com.sunwayworld.framework.at.annotation.AuditTrailType;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.context.concurrent.GikamConcurrentLocker;
import com.sunwayworld.framework.data.page.Page;
import com.sunwayworld.framework.exception.InvalidDataException;
import com.sunwayworld.framework.executor.ExecutorHelper;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.restful.data.RestJsonWrapperBean;
import com.sunwayworld.framework.spring.annotation.GikamBean;
import com.sunwayworld.framework.support.PersistableHelper;
import com.sunwayworld.framework.utils.CollectionUtils;
import com.sunwayworld.framework.utils.NumberUtils;
import com.sunwayworld.framework.utils.ObjectUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

@Repository
@GikamBean
public class LimsEquiptAcqConfigServiceImpl extends CoreEquiptAcqConfigServiceImpl implements LimsEquiptAcqConfigService {

    private static final Logger logger = LogManager.getLogger(LimsEquiptAcqConfigServiceImpl.class);

    @Autowired
    private LimsEquiptSerialNetRecService limsEquiptSerialNetRecService;

    @Autowired
    private NetEptSenderHelper netEptSenderHelper;

    @Autowired
    private final SimpMessagingTemplate template;

    public LimsEquiptAcqConfigServiceImpl(SimpMessagingTemplate template) {
        super(template);
        this.template = template;
    }

    @Autowired
    private LimsEquiptAcqConfigInstService limsEquiptAcqConfigInstService;

    @Autowired
    private CoreEquiptAcqConfigDao coreEquiptAcqConfigDao;

    @Autowired
    @Lazy
    private LimsEquipmentService equipmentService;

    public CoreEquiptAcqConfigDao getDao() {
        return this.coreEquiptAcqConfigDao;
    }

    @Override
    public void sendMessage(String equiptAcqConfigInstId) {
        //网口发送数据到设备，这里的id=ip:port
        //messageData 指令对象
        LimsEquiptAcqConfigInstBean configInstBean = limsEquiptAcqConfigInstService.selectFirstByFilter(SearchFilter.instance().match("id", equiptAcqConfigInstId).filter(MatchPattern.SEQ));
        CoreEquiptAcqConfigBean acqConfigBean = this.selectById(configInstBean.getAcqConfigId());
        NetEptSender eptSender = netEptSenderHelper.getCacheNetEptSender(acqConfigBean);
        String result = "";
        if(eptSender!=null && eptSender.isConnect()){
            result = eptSender.send(configInstBean);
        }else{
            if(eptSender!=null){
                eptSender.close();
            }
            throw new InvalidDataException("连接失败！");
        }
        if ("fail".equals(result)){
            throw new InvalidDataException("发送失败！");
        }
    }


    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.INSERT)
    public Long insertLimsAcqConfigInst(String id, RestJsonWrapperBean wrapperBean) {
        List<LimsEquiptAcqConfigInstBean> limsEquiptAcqConfigInstBeans = wrapperBean.parse(LimsEquiptAcqConfigInstBean.class);
        for (LimsEquiptAcqConfigInstBean limsEquiptAcqConfigInstBean : limsEquiptAcqConfigInstBeans) {
            limsEquiptAcqConfigInstBean.setId(ApplicationContextHelper.getNextIdentity());
            limsEquiptAcqConfigInstBean.setAcqConfigId(id);
        }
        limsEquiptAcqConfigInstService.getDao().insert(limsEquiptAcqConfigInstBeans);
        return limsEquiptAcqConfigInstBeans.get(0).getId();
    }

    @Override
    public Page<LimsEquiptAcqConfigInstBean> selectLimsAcqConfigInstPaginationByDcuConfigId(String id, RestJsonWrapperBean wrapperBean) {
        return limsEquiptAcqConfigInstService.selectPaginationByFilter(SearchFilter.instance().match("acqConfigId", id).filter(MatchPattern.EQ), wrapperBean);
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.DELETE)
    public void deleteLimsAcqConfigInst(String id, RestJsonWrapperBean wrapperBean) {
        limsEquiptAcqConfigInstService.delete(wrapperBean);
    }

    @Override
    public void pushEquiptMessage(String equiptId, Object message) {
        this.template.convertAndSend("/topic/tcp-ports/" + equiptId, message);
    }

    @Override
    public void testSend(String id, RestJsonWrapperBean wrapperBean) {
        // 配置信息
        CoreEquiptAcqConfigBean acqConfigBean = selectDetail(id);
        // 发送指令信息 至少包含 执行信息
        ExecutorHelper.submit(() -> {
            LimsEquiptAcqConfigInstBean instBean = wrapperBean.parseUnique(LimsEquiptAcqConfigInstBean.class);
            /*LimsProtocolHttpMessageSender httpMessageSender = new LimsProtocolHttpMessageSender();
            String response = httpMessageSender.send(acqConfigBean, instBean);
            // 解析返回数据
            String analysisData = response;
            logger.info("receive data from {}: {}", acqConfigBean.getIp(), response);
            if (!StringUtils.isEmpty(instBean.getScript())) {
                try {
                    List<AbstractLimsNetAcqReadData> resultList = LimsEquiptAcqResultAnalysisEngine.getEngine(instBean, response).analysis();
                    if (!CollectionUtils.isEmpty(resultList)) {
                        analysisData = JSONObject.toJSONString(resultList);
                    }
                } catch (Exception e) {
                    analysisData = "result analysis error";
                }

            }*/
//            limsEquiptSerialNetRecService.record(acqConfigBean, response, analysisData);
//            pushEquiptMessage(id, analysisData);
        });
    }

    @Override
    public List<LimsEquiptAcqConfigInstBean> selectInstructionSelectableList() {
        return limsEquiptAcqConfigInstService.selectSelectableList();
    }

    @Override
    public String closeConnect(String eptId) {
        CoreEquiptAcqConfigBean acqConfigBean = this.selectById(eptId);
        NetEptSender eptSender = netEptSenderHelper.getCacheNetEptSender(acqConfigBean);
        if(eptSender!=null){
            eptSender.close();
        }
        return "success";
    }

    @Override
    public String requestEquiptTempAndHum(String id) {
        LimsEquipmentBean equipBean = equipmentService.selectById(Long.parseLong(id));
        return limsEquiptAcqConfigInstService.requestEquiptTempAndHum(equipBean);
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.INSERT)
    public CoreEquiptAcqConfigBean selectById(String equiptId) {
        CoreEquiptAcqConfigBean dcuConfig = selectByIdIfPresent(equiptId);
        if (dcuConfig == null) {
            // 查询设备是否存在
            LimsEquipmentBean limsEquiptBean = equipmentService.selectById(NumberUtils.parseLong(equiptId));
            dcuConfig = new CoreEquiptAcqConfigBean();
            dcuConfig.setId(ObjectUtils.toString(limsEquiptBean.getId()));
            getDao().insert(dcuConfig);
        }
        return dcuConfig;
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.INSERT)
    public CoreEquiptAcqConfigBean selectDetail(String id) {
        // 查询配置，防止批量插入的没有同步dcuConfig 这里做个判断 有设备，但是没有配置详情的就给插入一条数据
        Map<String, Object> dcuConfig = getDao().selectDetail(id);
        if (CollectionUtils.isEmpty(dcuConfig)) {
            CoreEquiptAcqConfigBean insertDcu = new CoreEquiptAcqConfigBean();
            insertDcu.setId(id);
            getDao().insert(insertDcu);
            dcuConfig = getDao().selectDetail(id);
        }
        return PersistableHelper.mapToPersistable(dcuConfig, CoreEquiptAcqConfigBean.class);
    }

    @Override
    @Transactional
    public String connect(String id, RestJsonWrapperBean wrapper) {
        //重写connect，测试网口连接触发
        CoreEquiptAcqConfigBean acqConfig = this.selectDetail(id);
        GikamConcurrentLocker.block(acqConfig.getId());
        String netacqtype = acqConfig.getExt$Item("NETACQTYPE");
        String acqCategory = acqConfig.getAcqCategory();
        logger.info("----------->acqCategory={}",acqCategory);
        CountDownLatch connectLatch = new CountDownLatch(1);
        netEptSenderHelper.testConnect(acqConfig);
        //最多等待4s,
//        try {
//            connectLatch.await(4, TimeUnit.SECONDS);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        logger.info("启动测试连接结束....");
        NetEptSender cacheNetEptSender = netEptSenderHelper.getCacheNetEptSender(acqConfig);
        if(cacheNetEptSender!=null && cacheNetEptSender.isConnect()){
            return "success";
        }else{
            return "fail";
        }
    }

}
